#include "pch.h"
#include "Brushes.h"
#include <memory>
#include "ErrorCodes.h"

using namespace Platform;
using namespace Windows::Foundation;
using namespace concurrency;
using namespace Microsoft::WRL;

using namespace DXBase;
using namespace DXBase::D2D;

SolidColorBrush::SolidColorBrush()
{
	watcher.Target = this;

	Color = Windows::UI::Colors::Black;
	opacity = 1;
	transform = identity2d();
}
NativeBrush^ SolidColorBrush::GetNativeBrush()
{
	if (!nbrush)
	{
		if (!Context)
			throw ExHelper::CreateException(ErrorCodes::ContextNotSet);

		D2D1_BRUSH_PROPERTIES bProps = { opacity, makeD2D(transform) };
		HR2Ex(Context->m_d2dContext->CreateSolidColorBrush(DXBase::makeD2D(color), bProps, pbrush.GetAddressOf()));

		auto result = ref new NativeBrush();
		result->brush = pbrush;
		nbrush = result;
	}
	return nbrush;
}


LinearGradientBrush::LinearGradientBrush()
{
	watcher.Target = this;

	opacity = 1;
	transform = identity2d();
	endPoint = vector2(100, 100);
	gamma = D2D::ColorInterpolationMode::scRgb;
	emode = GradientSpreadMethod::Repeat;
}
NativeBrush^ LinearGradientBrush::GetNativeBrush()
{
	if (!nbrush)
	{
		if (!Context)
			throw ExHelper::CreateException(ErrorCodes::ContextNotSet);

		std::vector<D2D1_GRADIENT_STOP> vgrad;
		if (gradientStops)
		{
			for each (auto gs in gradientStops)
			{
				D2D1_GRADIENT_STOP s = { gs.position, DXBase::makeD2D(gs.color) };
				vgrad.push_back(s);
			}
		}
		if (!vgrad.size())
		{
			D2D1_GRADIENT_STOP s = { 0, { 0, 0, 0, 1 } };
			vgrad.push_back(s);
		}
		ComPtr<ID2D1GradientStopCollection> pGStop;
		HR2Ex(Context->m_d2dContext->CreateGradientStopCollection(
			&vgrad[0], (UINT32)vgrad.size(),
			static_cast<D2D1_GAMMA>(gamma), static_cast<D2D1_EXTEND_MODE>(emode),
			pGStop.GetAddressOf()));

		D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lgbProps = { makeD2D(startPoint), makeD2D(endPoint) };
		D2D1_BRUSH_PROPERTIES bProps = { opacity, makeD2D(transform) };

		HR2Ex(Context->m_d2dContext->CreateLinearGradientBrush(lgbProps, bProps, pGStop.Get(), pbrush.GetAddressOf()));

		auto result = ref new NativeBrush();
		result->brush = pbrush;
		nbrush = result;
	}
	return nbrush;
}


RadialGradientBrush::RadialGradientBrush()
{
	watcher.Target = this;

	opacity = 1;
	transform = identity2d();
	radius = Windows::Foundation::Size(100, 100);
	gamma = D2D::ColorInterpolationMode::scRgb;
	emode = GradientSpreadMethod::Repeat;
}
NativeBrush^ RadialGradientBrush::GetNativeBrush()
{
	if (!nbrush)
	{
		if (!Context)
			throw ExHelper::CreateException(ErrorCodes::ContextNotSet);

		std::vector<D2D1_GRADIENT_STOP> vgrad;
		if (gradientStops)
		{
			for each (auto gs in gradientStops)
			{
				D2D1_GRADIENT_STOP s = { gs.position, DXBase::makeD2D(gs.color) };
				vgrad.push_back(s);
			}
		}
		if (!vgrad.size())
		{
			D2D1_GRADIENT_STOP s = { 0, { 0, 0, 0, 1 } };
			vgrad.push_back(s);
		}
		ComPtr<ID2D1GradientStopCollection> pGStop;
		HR2Ex(Context->m_d2dContext->CreateGradientStopCollection(
			&vgrad[0], (UINT32)vgrad.size(),
			static_cast<D2D1_GAMMA>(gamma), static_cast<D2D1_EXTEND_MODE>(emode),
			pGStop.GetAddressOf()));

		D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES rgbProps = { makeD2D(center), makeD2D(offset), radius.Width, radius.Height };
		D2D1_BRUSH_PROPERTIES bProps = { opacity, makeD2D(transform) };

		HR2Ex(Context->m_d2dContext->CreateRadialGradientBrush(rgbProps, bProps, pGStop.Get(), pbrush.GetAddressOf()));

		auto result = ref new NativeBrush();
		result->brush = pbrush;
		nbrush = result;
	}
	return nbrush;
}


BitmapBrush::BitmapBrush()
{
	watcher.Target = this;

	opacity = 1;
	transform = identity2d();
	spreadX = spreadY = GradientSpreadMethod::Repeat;
	bmpIMode = BITMAP_INTERPOLATION_MODE::NEAREST_NEIGHBOR;
}
NativeBrush^ BitmapBrush::GetNativeBrush()
{
	if (!nbrush)
	{
		if (!Context)
			throw ExHelper::CreateException(ErrorCodes::ContextNotSet);
		if (!bitmap)
			throw ExHelper::CreateException(ErrorCodes::Empty);

		bitmap->Context = Context;
		bitmap->LoadDXData();

		D2D1_BITMAP_BRUSH_PROPERTIES bbProps = { static_cast<D2D1_EXTEND_MODE>(spreadX), static_cast<D2D1_EXTEND_MODE>(spreadY), static_cast<D2D1_BITMAP_INTERPOLATION_MODE>(bmpIMode) };
		D2D1_BRUSH_PROPERTIES bProps = { opacity, makeD2D(transform) };
		HR2Ex(Context->m_d2dContext->CreateBitmapBrush(bitmap->pBitmap.Get(), bbProps, bProps, pbrush.GetAddressOf()));

		auto result = ref new NativeBrush();
		result->brush = pbrush;
		nbrush = result;
	}
	return nbrush;
}
